package com.packet.cheng.interceptor;

import com.alibaba.fastjson.JSON;
import com.packet.cheng.annotation.LogAnnotation;
import com.packet.cheng.dto.SysLogDTO;
import com.packet.cheng.entity.User;
import com.packet.cheng.enumm.DataStatus;
import com.packet.cheng.service.SysLogService;
import com.packet.cheng.service.UserService;
import com.packet.cheng.util.R;
import com.packet.cheng.util.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Objects;
import com.packet.cheng.util.IpUtil;
/**
 * @version 1.0
 * @Author zaicheng
 * @Date 2024/2/20 23:05
 * @email 1204133120@qq.com
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    @Resource
    private SysLogService sysLogService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private UserService userService;
    // 定义切入点：
    @Pointcut("@annotation(com.packet.cheng.annotation.LogAnnotation)")
    public void logPointCut(){}


    // 定义环绕通知
    /** 环绕通知处理 */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        // 调用目标方法之前进行登录认证
        HttpServletRequest request = ServletUtils.getRequest();
        String token = request.getHeader("token");
        R<User> loginUser = userService.loginAuthticate(token);

        long beginTime = System.currentTimeMillis();
        try {
            // 调用目标方法，不写point.proceed()，方法不会调用,将结果返回
            Object result = point.proceed();

            // 计算执行时长
            long time = System.currentTimeMillis() - beginTime;

            // 保存日志
            saveLog(point,time, DataStatus.NORMAL, loginUser.getData(), request);

            return result;
        } catch (Exception e) {
            // 计算执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
            // 保存日志
            saveLog(point,time, DataStatus.REMOVE,loginUser.getData(),request);
            throw e;
        }
    }

    // 保存日志到数据库
    public void saveLog(ProceedingJoinPoint joinPoint, long time, Short status,User loginUser,HttpServletRequest request) throws Exception {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 通过反射获取目标方法
        Method method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(),signature.getParameterTypes());
        // 获取方法上的注解
        LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
        // 获取操作日志对象
        Class<SysLogDTO> sysLogOperationClass = SysLogDTO.class;
        SysLogDTO sysLogOperation = sysLogOperationClass.newInstance();
        if (!Objects.isNull(annotation)){
            sysLogOperation.setLogTitle(annotation.value());
        }
        String ipAddr = IpUtil.getIpAddr(request);
        // 根据ip地址解析ip属地,参考博客(https://www.jianshu.com/p/dd408fb40794)
        String ipRegion = IpUtil.getIpRegion(ipAddr);
        sysLogOperation.setIp(ipAddr);
        sysLogOperation.setIpRegion(ipRegion);
        sysLogOperation.setRequestUri(request.getRequestURI());
        sysLogOperation.setRequestMethod(request.getMethod());
        sysLogOperation.setRequestTime((int) time);
        sysLogOperation.setStatus(status);
        sysLogOperation.setCreateTime(LocalDateTime.now());
        sysLogOperation.setUpdateTime(LocalDateTime.now());
        sysLogOperation.setUsername(loginUser.getUsername());
        sysLogOperation.setCreateId(loginUser.getId());
        sysLogOperation.setUpdateId(loginUser.getId());
        // 获取参数
        Object[] args = joinPoint.getArgs();
        String params = JSON.toJSONString(args[0]);
        sysLogOperation.setRequestParams(params);
        // 保存数据
        sysLogService.insertSysLog(sysLogOperation);
    }
}
